/*
 * Functions to interract with virtiofs-pci
 */

#pragma once

//
// Located in the VIOFS_INKERNEL_REQUEST::CallerContext
//
typedef struct _VIOFSCALL_EXTENSION {
    ULONG       MdlsAllocated; // True if MDLs are allocated and must be freed

    PMDL        InputBufferMdl;
    PMDL        OutputBufferMdl;

    ULONG       InputBufferSize;
    ULONG       OutputBufferSize;

    struct fuse_in_header  *FuseInHdr;
    struct fuse_out_header *FuseOutHdr;

    PMDL        HdrMdl;       // Mdl with fuse-headers
    ULONG       InHdrSize;
    ULONG       OutHdrSize;

    UINT64      BytesReturned;
    KEVENT      CompleteEvent;
} VIOFSCALL_EXTENSION, * PVIOFSCALL_EXTENSION;

//
// Normally operation are called with big timeout.
// But if we fail, we switch to smaller.
//
#define NTTIME_UNITS_IN_SECOND   (10 * 1000 * 1000)
#define SUBMIT_VIOFS_TIMEOUT     (15ll * NTTIME_UNITS_IN_SECOND)
#define SUBMIT2_VIOFS_TIMEOUT    (2ll * NTTIME_UNITS_IN_SECOND)

//
// Open Viofs device
//
NTSTATUS
OpenViofsDevice(
    IN  PHWFS_DEVICE_EXTENSION  pDevExt);

//
// Close device
//
VOID
CloseViofsDevice(
    IN  PHWFS_DEVICE_EXTENSION  pDevExt);

//
// Allocate request to VIOFS with specified buffers.
// Buffers must be allocated in kernel, in non-paged pool
//
PVIOFS_INKERNEL_REQUEST
AllocViofsRequestWithBuffer(
    IN  PHWFS_DEVICE_EXTENSION  pDevExt,
    IN  ULONG FuseInHdrSize,
    IN  ULONG FuseOutHdrSize,
    IN  PVOID InputBuffer,
    IN  ULONG InputBufferSize,
    IN  PVOID OutputBuffer,
    IN  ULONG OutputBufferSize);

//
// Allocate request to VIOFS with buffers described by MDLs
// @param MdlSkipPages:
//      Skip that number of pages from start of Mdl
//      while filling SG of request
//
PVIOFS_INKERNEL_REQUEST
AllocViofsRequestWithMdl(
    IN  PHWFS_DEVICE_EXTENSION  pDevExt,
    IN  ULONG FuseInHdrSize,
    IN  ULONG FuseOutHdrSize,
    IN  ULONG MdlSkipPages,
    IN  PMDL  InputBuffer,
    IN  ULONG InputBufferSize,
    IN  PMDL  OutputBuffer,
    IN  ULONG OutputBufferSize);

//
// Free the request
//
VOID
FreeViofsRequest(
    IN  PVIOFS_INKERNEL_REQUEST pRequest);

//
// Synchronously submit request to viofs
//
NTSTATUS
SubmitViofsRequest(
    IN  PHWFS_DEVICE_EXTENSION  pDevExt,
    IN  PVIOFS_INKERNEL_REQUEST pRequest);
